#include "libyuv.h"
#include <jni.h>
#include <android\bitmap.h>

extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_ABGRToNV21(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray abgr, jbyteArray nv21) {
    jbyte *dst_nv21 = env->GetByteArrayElements(nv21, JNI_FALSE);
    jbyte *src_abgr = env->GetByteArrayElements(abgr, JNI_FALSE);
    int ret = libyuv::ABGRToNV21((uint8_t*) src_abgr, width * 4,
                         (uint8_t*) dst_nv21, width,
                         (uint8_t*) dst_nv21 + (width * height),
                          width, width, height);
    env->ReleaseByteArrayElements(nv21, dst_nv21, JNI_OK);
    env->ReleaseByteArrayElements(abgr, src_abgr, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_BGRAToARGB(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray bgra, jbyteArray argb) {
    jbyte *src_bgra = env->GetByteArrayElements(bgra, JNI_FALSE);
    jbyte *dst_argb = env->GetByteArrayElements(argb, JNI_FALSE);
    int ret = libyuv::BGRAToARGB((const uint8_t*) src_bgra, width * 4, (uint8_t*) dst_argb, width * 4, width, height);
    env->ReleaseByteArrayElements(bgra, src_bgra, JNI_OK);
    env->ReleaseByteArrayElements(argb, dst_argb, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_ARGBToBGRA(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray argb, jbyteArray bgra) {
    jbyte *src_argb = env->GetByteArrayElements(argb, JNI_FALSE);
    jbyte *dst_bgra = env->GetByteArrayElements(bgra, JNI_FALSE);
    int ret = libyuv::ARGBToBGRA((const uint8_t*) src_argb, width * 4, (uint8_t*) dst_bgra, width * 4, width, height);
    env->ReleaseByteArrayElements(argb, src_argb, JNI_OK);
    env->ReleaseByteArrayElements(bgra, dst_bgra, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_NV21ToABGR(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray nv21, jbyteArray abgr) {
    jbyte *src_nv21 = env->GetByteArrayElements(nv21, JNI_FALSE);
    jbyte *dst_argb = env->GetByteArrayElements(abgr, JNI_FALSE);
    int ret = libyuv::NV21ToABGR((const uint8_t*) src_nv21, width,
                                 (const uint8_t*) src_nv21 + width * height, width,
                                 (uint8_t*) dst_argb, width * 4, width, height);
    env->ReleaseByteArrayElements(nv21, src_nv21, JNI_OK);
    env->ReleaseByteArrayElements(abgr, dst_argb, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_NV21ToI420(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray nv21, jbyteArray i420) {
    jbyte *src_nv21 = env->GetByteArrayElements(nv21, JNI_FALSE);
    jbyte *dst_i420 = env->GetByteArrayElements(i420, JNI_FALSE);
    int ret = libyuv::NV21ToI420((const uint8_t*) src_nv21, width, (const uint8_t*) src_nv21 + width * height, width,
                                 (uint8_t*) dst_i420, width, (uint8_t*) dst_i420 + width * height, width >> 1,
                                 (uint8_t*) dst_i420 + width * height + (width >> 1) * (height >> 1), width >> 1, width, height);
    env->ReleaseByteArrayElements(nv21, src_nv21, JNI_OK);
    env->ReleaseByteArrayElements(i420, dst_i420, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_I420Rotate(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray src, jbyteArray dst, jint rotate) {
    libyuv::RotationModeEnum rotationModeEnum = libyuv::RotationModeEnum::kRotate0;
    char mode = 1;
    switch (rotate) {
        case 90:
            rotationModeEnum = libyuv::RotationModeEnum::kRotate90;
            mode = 0;
            break;
        case 180:
            rotationModeEnum = libyuv::RotationModeEnum::kRotate180;
            break;
        case 270:
            rotationModeEnum = libyuv::RotationModeEnum::kRotate270;
            mode = 0;
            break;
    }

    jbyte *src_i420 = env->GetByteArrayElements(src, JNI_FALSE);
    jbyte *dst_i420 = env->GetByteArrayElements(dst, JNI_FALSE);
    libyuv::I420Rotate((const uint8_t*) src_i420, width,
                       (const uint8_t*) src_i420 + width * height, width >> 1,
                       (const uint8_t*) src_i420 + width * height + (width >> 1) * (height >> 1),width >> 1,
                       (uint8_t*) dst_i420, mode ? width : height,
                       (uint8_t*) dst_i420 + width * height, mode ? width >> 1 : height >> 1,
                       (uint8_t*) dst_i420 + width * height + (width >> 1) * (height >> 1),mode ? width >> 1 : height >> 1,
                       width, height, rotationModeEnum);
    env->ReleaseByteArrayElements(src, src_i420, JNI_OK);
    env->ReleaseByteArrayElements(dst, dst_i420, JNI_OK);
    return 0;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_I420ToABGR(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray i420, jbyteArray abgr) {
    jbyte *src_i420 = env->GetByteArrayElements(i420, JNI_FALSE);
    jbyte *dst_abgr = env->GetByteArrayElements(abgr, JNI_FALSE);
    int ret = libyuv::I420ToABGR((const uint8_t*) src_i420, width,
                                 (const uint8_t*) src_i420 + width * height, width >> 1,
                                 (const uint8_t*) src_i420 + width * height + (width >> 1) * (height >> 1),width >> 1,
                                 (uint8_t*) dst_abgr, width * 4, width, height);
    env->ReleaseByteArrayElements(i420, src_i420, JNI_OK);
    env->ReleaseByteArrayElements(abgr, dst_abgr, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_bitmapToNv21(JNIEnv *env, jclass clazz, jobject bitmap,
                                          jbyteArray nv21) {
    AndroidBitmapInfo bitmapInfo;
    AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
    if (ANDROID_BITMAP_FORMAT_RGBA_8888 != bitmapInfo.format) {
        return -1;
    }
    int width = (int) bitmapInfo.width;
    int height = (int) bitmapInfo.height;

    uint8_t *src_abgr;
    AndroidBitmap_lockPixels(env, bitmap, (void **) &src_abgr);
    AndroidBitmap_unlockPixels(env, bitmap);

    jbyte *dst_nv21 = env->GetByteArrayElements(nv21, JNI_FALSE);
    int ret = libyuv::ABGRToNV21((uint8_t*) src_abgr, width * 4,
                                 (uint8_t*) dst_nv21, width,
                                 (uint8_t*) dst_nv21 + (width * height),
                                 width, width, height);
    env->ReleaseByteArrayElements(nv21, dst_nv21, JNI_OK);
    return ret;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_caiguoping_yuv_Test_ARGBRotate(JNIEnv *env, jclass clazz, jint width, jint height,
                                        jbyteArray src, jbyteArray dst, jint rotate) {
    char flag = 0;
    libyuv::RotationModeEnum mode = libyuv::kRotate0;
    switch (rotate) {
        case 90:
            mode = libyuv::kRotate90;
            flag = 1;
            break;
        case 180:
            mode = libyuv::kRotate180;
            break;
        case 270:
            mode = libyuv::kRotate270;
            flag = 1;
            break;
        default:
            break;
    }

    jbyte *src_argb = env->GetByteArrayElements(src, JNI_FALSE);
    jbyte *dst_argb = env->GetByteArrayElements(dst, JNI_FALSE);
    int ret = libyuv::ARGBRotate((const uint8_t*) src_argb, width * 4,
                                 (uint8_t*) dst_argb, flag ? height * 4 : width * 4,
                                 width, height, mode);
    env->ReleaseByteArrayElements(src, src_argb, JNI_OK);
    env->ReleaseByteArrayElements(dst, dst_argb, JNI_OK);
    return ret;
}